﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace AmuTools.Web
{
    public class WebRequestHelper
    {
        public HttpWebRequest HttpWebRequest { get; private set; }
        public HttpWebResponse HttpWebResponse{ get; private set; }

        public WebRequestHelper(string url, CookieContainer cookie = null)
        {
            HttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
            if(cookie != null)
            {
                HttpWebRequest.CookieContainer = cookie;
            }
        }

        public void SetJsonData(object obj)
        {
            this.HttpWebRequest.Method = "POST";
            this.HttpWebRequest.ContentType = "application/json";

            Stream reqStream = this.HttpWebRequest.GetRequestStream();
            string json = JsonConvert.SerializeObject(obj);
            byte[] jsonBytes = Encoding.UTF8.GetBytes(json);
            reqStream.Write(jsonBytes, 0, jsonBytes.Length);
            reqStream.Close();
        }

        public void SetFormData(FormData form)
        {
            this.HttpWebRequest.Method = "POST";
            this.HttpWebRequest.ContentType = "multipart/form-data; boundary=" + form.Boundary;

            Stream reqStream = this.HttpWebRequest.GetRequestStream();
            form.Render(reqStream);
            reqStream.Close();
        }

        public HttpWebResponse GetResponse()
        {
            this.HttpWebResponse = (HttpWebResponse)this.HttpWebRequest.GetResponse();
            return this.HttpWebResponse;
        }

        public string ReadResponse()
        {
            StreamReader sr = new StreamReader(this.HttpWebResponse.GetResponseStream(), Encoding.UTF8);
            return sr.ReadToEnd();
        }

        public T ReadResponse<T>()
        {
            string temp = ReadResponse();
            return JsonConvert.DeserializeObject<T>(temp);
        }
    }

    public class FormData
    {
        public string Boundary { get; private set; }
        public List<FormItem> FormItems { get; private set; }

        public FormData()
        {
            FormItems = new List<FormItem>();
            Boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
        }

        public void Render(Stream stream)
        {
            byte[] bytes = Encoding.UTF8.GetBytes($"\r\n--{Boundary}\r\n");
            foreach(FormItem item in FormItems)
            {
                stream.Write(bytes, 0, bytes.Length);
                item.Render(stream);
            }

            bytes = Encoding.UTF8.GetBytes($"\r\n--{Boundary}--");
            stream.Write(bytes, 0, bytes.Length);
        }
    }

    public class FormFileItem : FormItemBase, FormItem
    {
        public string FileName { get; private set; }

        public FormFileItem(string name, string fileName)
        {
            Name = name;
            FileName = fileName;
            Value = fileName;
        }

        public void Render(Stream stream)
        {
            string temp =
                $"Content-Disposition: form-data; name=\"{Name}\"; filename=\"{FileName}\"\r\n" +
                $"Content-Type: application/octet-stream\r\n" +
                $"\r\n";

            byte[] bytes = Encoding.UTF8.GetBytes(temp);
            byte[] fileBytes = FileBinaryConvertHelper.File2Bytes(FileName);
            stream.Write(bytes, 0, bytes.Length);
            stream.Write(fileBytes, 0, fileBytes.Length);
        }
    }

    public class FormTextItem : FormItemBase, FormItem
    {
        public FormTextItem(string name, string value)
        {
            Name = name;
            Value = value;
        }

        public void Render(Stream stream)
        {
            string temp = 
                $"Content-Disposition: form-data; name=\"{Name}\"\r\n" +
                $"\r\n" +
                $"{Value}";
            byte[] bytes = Encoding.UTF8.GetBytes(temp);
            stream.Write(bytes, 0, bytes.Length);
        }
    }

    public class FormItemBase
    {
        public string Name { get; protected set; }
        public string Value { get; protected set; }
        public string ConentType { get; protected set; }

        public string GetName()
        {
            return Name;
        }

        public string GetContentType()
        {
            return this.ConentType;
        }
    }

    public interface FormItem
    {
        string GetName();
        string GetContentType();
        void Render(Stream stream);
    }

    /// <summary>
    /// 工具类：文件与二进制流间的转换
    /// </summary>
    public class FileBinaryConvertHelper
    {
        /// <summary>
        /// 将文件转换为byte数组
        /// </summary>
        /// <param name="path">文件地址</param>
        /// <returns>转换后的byte数组</returns>
        public static byte[] File2Bytes(string path)
        {
            if (!System.IO.File.Exists(path))
            {
                return new byte[0];
            }

            FileInfo fi = new FileInfo(path);
            byte[] buff = new byte[fi.Length];

            FileStream fs = fi.OpenRead();
            fs.Read(buff, 0, Convert.ToInt32(fs.Length));
            fs.Close();

            return buff;
        }

        /// <summary>
        /// 将byte数组转换为文件并保存到指定地址
        /// </summary>
        /// <param name="buff">byte数组</param>
        /// <param name="savepath">保存地址</param>
        public static void Bytes2File(byte[] buff, string savepath)
        {
            if (System.IO.File.Exists(savepath))
            {
                System.IO.File.Delete(savepath);
            }

            FileStream fs = new FileStream(savepath, FileMode.CreateNew);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(buff, 0, buff.Length);
            bw.Close();
            fs.Close();
        }
    }
}
